#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
#include "user.h"
#include "cloud.h"


void generate_randomid(User *u) //初始化随机标识符
{
    for (size_t i = 0; i < TABLE_SIZE; i++) {
        u->my_Hashtable->HT[i]->randomId = rand() % 1000; //获得每个哈希桶对应的随机标识
        u->my_o_table->ox[i]->randomId = u->my_Hashtable->HT[i]->randomId; //将随机标识传递到o(x)表中
        u->my_root_table->r_table[i]->randomId = u->my_Hashtable->HT[i]->randomId; // 将随机标识传递到root 表中
        u->my_z_table->ztable[i]->randomId = u->my_Hashtable->HT[i]->randomId; // 将随机标识传递到z(x)表中
        u->my_o_hat_table->ohat[i]->randomId = u->my_Hashtable->HT[i]->randomId; // 将随机标识传递到o_hat(x)表中
        u->label[i] = u->my_Hashtable->HT[i]->randomId; //将随机标识传递到label表里
        u->label_hat[i] = u->my_Hashtable->HT[i]->randomId; //将随机标识传到o_hat 的随机标识表里
    }
}


void generate_roots(User *u) //生成每个用户的随机数表
{
    for (size_t i = 0; i < TABLE_SIZE; i++) // 对表进行循环
    {
        for (size_t j = 0; j < BUCKET_SIZE; j++) // 对表中每个位置进行循环
        {
            u->my_root_table->r_table[i]->root[j] = (rand() % 5 ) + 1;
        }
    }
}

void generate_polynomial(User *u) {
    // 初始化多项式系数数组，系数初始为0
    long long coefficients[BUCKET_SIZE+1];
    coefficients[0] = 1;
    for (int i = 1; i <= BUCKET_SIZE; i++) {
        coefficients[i] = 0;
    }

    // 使用多项式展开公式进行逐步展开
    for (size_t j = 0; j < TABLE_SIZE; j++) {
        coefficients[0] = 1;
        for (int i = 1; i <= BUCKET_SIZE; i++) {
            coefficients[i] = 0;
        }
        for (int i = 0; i < BUCKET_SIZE; i++) {
            //每个桶的P（x），把根调用进去
            int root = u->my_root_table->r_table[j]->root[i];

            // 从高次项开始更新系数，使用展开公式
            for (int k = i; k >= 0; k--) {
                coefficients[k + 1] += coefficients[k];
                coefficients[k] *= -root;
            }
        }

        for (size_t o = 0; o < BUCKET_SIZE + 1; o++) {
            u->my_Hashtable->HT[j]->Px_coef[o] = coefficients[o]; // 构造哈希表
        }
        u->my_num_table->num[j] = 0; //在这里一同先进行计数的初始化。
    }
}

void generate_divide_polynomial(User *u) {
    // 将P(x)分割为o(x)和z(x) (初始化阶段)

    for (size_t i = 0; i < TABLE_SIZE; i++) // 完成o(x)和z(x)表的构建
    {
        // 将随机系数发送给o(x)和o_hat(x)
        for (int j = 0; j < BUCKET_SIZE + 1; j++) {
            u->my_o_table->ox[i]->ox_coef[j] = rand();
            u->my_o_hat_table->ohat[i]->ox_coef[j] = u->my_o_table->ox[i]->ox_coef[j];
        }

        // 将另一部分发送给z(x)
        for (int j = 0; j < BUCKET_SIZE + 1; j++) {
            u->my_z_table->ztable[i]->zx_coef[j] =
                    u->my_Hashtable->HT[i]->Px_coef[j] - u->my_o_table->ox[i]->ox_coef[j];
        }
    }
}

void generate_user_state(User *u){

    u->user_state = 0;//刚开始，我们让用户处于离线状态

}


// 用 Fisher-Yates 洗牌算法混淆多项式的存储顺序
void shufflePolynomials(User *u) {
    //把o(x)的顺序传输过来，混淆后传输成o_hat(x)
    long long temp[BUCKET_SIZE + 1];
    int temp_randomId;
    int temp_number = 0;

    for (int i = TABLE_SIZE-1; i > 0; i--) {
        int j = rand() % (i + 1);
        //更新一下每个桶对应的随机标识
        temp_randomId = u->my_o_hat_table->ohat[i]->randomId; //把第i个桶的随机标识先保留起来
        u->my_o_hat_table->ohat[i]->randomId = u->my_o_hat_table->ohat[j]->randomId; //将第j个桶的随机标识放到第i个桶中
        u->label_hat[i] = u->label_hat[j]; //用户ohat表的第i个随机标识换成第j个随机标识
        u->my_o_hat_table->ohat[j]->randomId = temp_randomId; //将第i个桶的随机标识放入第j个桶中
        u->label_hat[j] = temp_randomId; //用户ohat表的第j个随机标识换成第i个随机标识

        temp_number = u->shuffle_lable_matrix[1][i];
        u->shuffle_lable_matrix[1][i] = u->shuffle_lable_matrix[1][j];
        u->shuffle_lable_matrix[1][j] = temp_number;

        for (size_t k = 0; k < BUCKET_SIZE + 1; k++) {
            temp[k] = u->my_o_hat_table->ohat[i]->ox_coef[k];
            u->my_o_hat_table->ohat[i]->ox_coef[k] = u->my_o_hat_table->ohat[j]->ox_coef[k];
            u->my_o_hat_table->ohat[j]->ox_coef[k] = temp[k];
        }
    }
}

void send_o_hat_table_ToCloud(CloudServer *c, User *u) {
    //将o_hat表发送给云服务器
    for (int i = 0; i < TABLE_SIZE; i++) {
        for (int j = 0; j < BUCKET_SIZE + 1; j++) {
            c->user_o_hat_table[u->User_symbol]->ohat[i]->ox_coef[j] = u->my_o_hat_table->ohat[i]->ox_coef[j];
        }
        c->user_o_hat_table[u->User_symbol]->ohat[i]->randomId = u->my_o_hat_table->ohat[i]->randomId;
    }
}

void generate(User *u, CloudServer *c) {
    //初始化一个用户

    generate_roots(u);//给用户生成随机数根
    generate_randomid(u); //给用户生成随机标识
    generate_polynomial(u); //用户初始化哈希表
    generate_divide_polynomial(u); //将初始化后的哈希表分为两部分
    shufflePolynomials(u); //混淆生成的o(x)表
    send_o_hat_table_ToCloud(c, u); //将混淆后的表发送给云平台
    user_get_hashseed(u,c);//将公用的hashseed存放到本地
    generate_user_state(u);
}